﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Ps3RemoteSleep
{
    public class Ps3RemoteSleepClass
    {
        /// <summary>
        /// Passes log event events to the owner 
        /// </summary>
        public event EventHandler<EventLogItemArgs> OnEvent = null;

        /// <summary>
        /// Places the remote control in a sleep state by disabling and re-enabling the HID service of the remote control, while temporarily switching off Windows hardware insertion and removal sounds
        /// </summary>
        /// <returns>Boolean value indicates the sucess of the operation. False could mean that the remote is not connected, or already in a sleep state.</returns>
        public bool HibernateRemote()
        {
            string deviceConnectSoundFile = "";
            string deviceDisconnectSoundFile = "";
            bool ok = false;

            try
            {
                LogEvent("Creating Bluetooth client");
                InTheHand.Net.Sockets.BluetoothClient cli = new InTheHand.Net.Sockets.BluetoothClient(); //Create a bluetooth client for the enquiry
                LogEvent("Discovering devices");
                cli.InquiryLength = new TimeSpan(0, 0, 1); //Discover new devices for 1sec, actually we only really need to get the remembered/paired device.
                InTheHand.Net.Sockets.BluetoothDeviceInfo[] devs = cli.DiscoverDevices();

                LogEvent("Finding 'BD Remote Control'");
                InTheHand.Net.Sockets.BluetoothDeviceInfo remoteInfo = devs.First(dev => dev.DeviceName == "BD Remote Control"); //Find the remote control
                
                //The next line will cause a SocketException if the device is already in sleep mode
                LogEvent("Checking sleep state, enumerating services");
                InTheHand.Net.Bluetooth.ServiceRecord[] services = remoteInfo.GetServiceRecords(InTheHand.Net.Bluetooth.BluetoothService.HumanInterfaceDevice);

                if (remoteInfo != null)
                {
                    LogEvent("Remote found with address: "+remoteInfo.DeviceAddress.ToString());
                    //remoteInfo.DeviceAddress containts the address of the remote, could possibly store and reuse this later.

                    //Store the user hardware sounds and blank them
                    LogEvent("Get current hardware sounds");
                    deviceConnectSoundFile = (string)Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\AppEvents\Schemes\Apps\.Default\DeviceConnect\.Current", "", "");
                    deviceDisconnectSoundFile = (string)Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\AppEvents\Schemes\Apps\.Default\DeviceDisconnect\.Current", "", "");
                    try
                    {
                        LogEvent("Disable hardware sounds");
                        Microsoft.Win32.Registry.SetValue(@"HKEY_CURRENT_USER\AppEvents\Schemes\Apps\.Default\DeviceConnect\.Current", "", "");
                        Microsoft.Win32.Registry.SetValue(@"HKEY_CURRENT_USER\AppEvents\Schemes\Apps\.Default\DeviceDisconnect\.Current", "", "");

                        //Switch off the HID service
                        LogEvent("Switch off remote's HID service");
                        remoteInfo.SetServiceState(InTheHand.Net.Bluetooth.BluetoothService.HumanInterfaceDevice, false);

                        //Re-enable off the HID service
                        LogEvent("Switch on remote's HID service");
                        remoteInfo.SetServiceState(InTheHand.Net.Bluetooth.BluetoothService.HumanInterfaceDevice, true);

                        ok = true;
                    }
                    finally
                    {
                        //Restore the user hardware sounds 
                        try
                        {
                            LogEvent("Restoring hardware sounds");
                            System.Threading.Thread.Sleep(1000);
                            Microsoft.Win32.Registry.SetValue(@"HKEY_CURRENT_USER\AppEvents\Schemes\Apps\.Default\DeviceConnect\.Current", "", deviceConnectSoundFile);
                            Microsoft.Win32.Registry.SetValue(@"HKEY_CURRENT_USER\AppEvents\Schemes\Apps\.Default\DeviceDisconnect\.Current", "", deviceDisconnectSoundFile);
                        }
                        catch { }
                    }
                }
                else
                    throw new Exception("PS3 remote could not be found.");
            }
            catch (System.Net.Sockets.SocketException ex)
            {
                LogEvent("The device is already in a sleep state.");
                return false;
            }
            catch (Exception ex)
            {
                LogEvent("Exception: " + ex.Message);
                return false;
            }           
            
            return ok;
        }

        protected void LogEvent(string aText)
        {
            if (OnEvent != null)
                OnEvent(this, new EventLogItemArgs(aText));
        }
    }

    public class EventLogItemArgs : EventArgs
    {
        public string EventText { get; protected set; }
        public EventLogItemArgs(string aText)
        {
            EventText = aText;
        }
    }
}
